import time
from flask import jsonify
from pyModbusTCP.client import ModbusClient

# 放料指令
TAKE_MATERIALS = 1
# 取料指令
PUT_MATERIALS = 2


# import getLongMenResult

def setup_modbus_client(host, port):
    # 设置Modbus TCP客户端
    client = ModbusClient(host=host, port=port)
    if not client.is_open:
        if not client.open():
            print(f"无法连接到Modbus设备：龙门；地址：{host}:{port}")
            exit(1)
        else:
            print(f"成功连接到Modbus设备：龙门；地址：{host}:{port}")
    return client


# 初始化Modbus客户端
client_connection = setup_modbus_client("192.168.1.16", 502)


# 机械臂类
class RoboticArm:
    def __init__(self, work, status):
        # 机械臂工作状态，可能的取值为 "work"（工作中） 或 "notwork"（空闲）
        self.work = ''
        # 取料/放料状态，可能的取值为 "take"（取料中） 或 "put"（放料中）
        self.status = ''


robotic_arm = RoboticArm("", "")  # 确保传入两个参数


# 原料仓库类
# Parameter:
# x1,x2,y1,y2:int, 原料仓库坐标
# status:str, 原料仓库状态，"have"表示仓库中有原料，"not"表示仓库中没有
# name:str, 原料名称
class WareItem:
    def __init__(self, x1, x2, y1, y2, status, name):
        self.x1 = x1
        self.x2 = x2
        self.y1 = y1
        self.y2 = y2
        self.status = status
        self.name = name

        # 获取x坐标

    def get_x_coordinate(self):
        # 返回x坐标。将self.x1左移16位，然后与self.x2进行按位或运算，最终得到一个32位整数，表示x坐标。
        return (self.x1 << 16) | self.x2

        # 获取y坐标

    def get_y_coordinate(self):
        # 返回y坐标。将self.y1左移16位，然后与self.y2进行按位或运算，最终得到一个32位整数，表示y坐标。
        return (self.y1 << 16) | self.y2


# 成品库（OK）类
# Parameter:
# x1,x2,y1,y2:int, 成品仓库（OK）坐标
# status:str, 成品仓库（OK）状态，"empty"表示仓库为空，可以放置成品，"FullOK"表示仓库已满
# name:str, 成品名称
class OKItem:
    def __init__(self, x1, x2, y1, y2, status, name):
        self.x1 = x1
        self.x2 = x2
        self.y1 = y1
        self.y2 = y2
        self.status = status
        self.name = name

        # 获取x坐标

    def get_x_coordinate(self):
        # 返回x坐标。将self.x1左移16位，然后与self.x2进行按位或运算，最终得到一个32位整数，表示x坐标。
        return (self.x1 << 16) | self.x2

        # 获取y坐标

    def get_y_coordinate(self):
        # 返回y坐标。将self.y1左移16位，然后与self.y2进行按位或运算，最终得到一个32位整数，表示y坐标。
        return (self.y1 << 16) | self.y2


# 成品库（NG）类
# Parameter:
# x1,x2,y1,y2:int, 成品仓库（NG）坐标
# status:str, 成品仓库（NG）状态，"empty"表示仓库为空，可以放置成品，"FullNG"表示仓库已满
# name:str, 成品名称
class NGItem:
    def __init__(self, x1, x2, y1, y2, status, name):
        self.x1 = x1
        self.x2 = x2
        self.y1 = y1
        self.y2 = y2
        self.status = status
        self.name = name

        # 获取x坐标

    def get_x_coordinate(self):
        # 返回x坐标。将self.x1左移16位，然后与self.x2进行按位或运算，最终得到一个32位整数，表示x坐标。
        return (self.x1 << 16) | self.x2

        # 获取y坐标

    def get_y_coordinate(self):
        # 返回y坐标。将self.y1左移16位，然后与self.y2进行按位或运算，最终得到一个32位整数，表示y坐标。
        return (self.y1 << 16) | self.y2


def send_XY(client_connection, X, Y):
    # 定义寄存器值
    register_values = {
        0x0002: X[0],  # X[0]对应 x1
        0x0003: X[1],  # X[1]对应 x2
        0x0006: Y[0],  # Y[0]对应 y1
        0x0007: Y[1],  # Y[1]对应 y2
        0x0004: 0x0000,
        0x0005: 0x0000,
        0x0008: 0x0000,
        0x0009: 0x0000
    }
    # 定义结果字典
    results = {}
    # 遍历寄存器值并写入到客户端连接
    # items:字典方法，用于返回一个包含字典所有键值对的可迭代对象。
    for addr, value in register_values.items():
        results[addr] = client_connection.write_single_register(addr, value)

    return results


# 控制机械臂移动
def send_move(client_connection,order):
    addr = 0x0000  # 寄存器地址
    result = client_connection.write_single_register(addr, order)
    return result


# 获取原料
def getMaterial(user_input):
    global wareHouse  # 声明 wareHouse 为全局变量

    for stash in wareHouse:  # 循环遍历 wareHouse
        if stash.status == "have":  # if wareHouse:#len(wareHouse) >= 1
            X = (stash.x1, stash.x2)
            Y = (stash.y1, stash.y2)
            # results存储函数调用结果
            results = send_XY(client_connection, X, Y)

            # 抽取成 send_move函数
            order = TAKE_MATERIALS
            result = send_move(client_connection,order)

            stash.status = "not"
            removed_masterial = stash.name
            return f"取料完成，已取得原料：{removed_masterial}"

    return "仓库中没有原料"


# 放置成品
def putMaterial(user_input):
    global NGHouse
    global OKHouse

    if user_input == "放料OK":
        for stash in OKHouse:
            if stash.status == "empty":
                X = (stash.x1, stash.x2)
                Y = (stash.y1, stash.y2)
                results = send_XY(client_connection, X, Y)

                order = PUT_MATERIALS
                result = send_move(client_connection,order)

                stash.status = "FullOK"
                return f"放料完成，已放置到：{stash.name}"

        for stash in NGHouse:
            if stash.status == "empty":
                X = (stash.x1, stash.x2)
                Y = (stash.y1, stash.y2)
                results = send_XY(client_connection, X, Y)

                order = PUT_MATERIALS
                result = send_move(client_connection,order)

                stash.status = "FullOK"
                return f"OK库已满，放料完成，已暂时放置到：{stash.name}"
        return "成品库已满"

    elif user_input == "放料NG":
        for stash in NGHouse:
            if stash.status == "empty":
                X = (stash.x1, stash.x2)
                Y = (stash.y1, stash.y2)
                results = send_XY(client_connection, X, Y)

                order = PUT_MATERIALS
                result = send_move(client_connection,order)

                stash.status = "FullNG"
                return f"放料完成，已放置到：{stash.name}"
        for stash in OKHouse:
            if stash.status == "empty":
                X = (stash.x1, stash.x2)
                Y = (stash.y1, stash.y2)
                results = send_XY(client_connection, X, Y)

                order = PUT_MATERIALS
                result = send_move(client_connection,order)

                stash.status = "FullNG"
                return f"NG库已满，放料完成，已暂时放置到：{stash.name}"
        return "成品库已满"


def getHouseStatus(shuru):
    iswork = robotic_arm.work
    status = robotic_arm.status
    if iswork == "work":
        work = shuru
    else:
        work = ""
    if status == "put":
        status = "put"
    else:
        status = "take"
    stash1 = wareHouse[0]
    stash1_name = stash1.name
    stash1_status = stash1.status

    stash2 = wareHouse[1]
    stash2_name = stash2.name
    stash2_status = stash2.status

    stash3 = NGHouse[0]
    stash3_name = stash3.name
    stash3_status = stash3.status

    stash4 = OKHouse[0]
    stash4_name = stash4.name
    stash4_status = stash4.status

    # 是否工作、取料/放料、库名字、库状态
    return iswork, work, status, stash1_name, stash1_status, stash2_name, stash2_status, stash3_name, stash3_status, stash4_name, stash4_status


# 假设仓库中的原料库
# 创建 WareItem 对象并加入列表
wareHouse = [
    WareItem(0x43db, 0x0000, 0x4385, 0x8000, "have", "原料1"),
    WareItem(0x441f, 0x8000, 0x4384, 0x8000, "have", "原料2"),
    WareItem(0x43db, 0x0000, 0x4385, 0x8000, "have", "原料3"),
    WareItem(0x441f, 0x8000, 0x4384, 0x8000, "have", "原料4"),
    WareItem(0x43db, 0x0000, 0x4385, 0x8000, "have", "原料5")
]

# 创建 NGItem 对象并加入列表
NGHouse = [
    NGItem(0x43db, 0x0000, 0x4220, 0x0000, "empty", "NG1"),
    NGItem(0x43db, 0x0000, 0x4220, 0x0000, "empty", "NG2"),
    NGItem(0x43db, 0x0000, 0x4220, 0x0000, "empty", "NG3"),
    NGItem(0x43db, 0x0000, 0x4220, 0x0000, "empty", "NG4"),
    NGItem(0x43db, 0x0000, 0x4220, 0x0000, "empty", "NG5")
]

# 创建 OKItem 对象并加入列表
OKHouse = [
    OKItem(0x4420, 0x0000, 0x4220, 0x0000, "empty", "OK1"),
    OKItem(0x4420, 0x0000, 0x4220, 0x0000, "empty", "OK2"),
    OKItem(0x4420, 0x0000, 0x4220, 0x0000, "empty", "OK3"),
    OKItem(0x4420, 0x0000, 0x4220, 0x0000, "empty", "OK4"),
    OKItem(0x4420, 0x0000, 0x4220, 0x0000, "empty", "OK5")
]


def get_coordinates(stashes):
    for stash in stashes:
        x_coordinate = stash.get_x_coordinate()
        y_coordinate = stash.get_y_coordinate()
        # print(f"{item.name} 的 x 坐标为 {x_coordinate}，y 坐标为 {y_coordinate}")


# 获取原料的 x 和 y 坐标
get_coordinates(wareHouse)

# 获取 NGItem 的 x 和 y 坐标
get_coordinates(NGHouse)

# 获取 OKItem 的 x 和 y 坐标
get_coordinates(OKHouse)


# robotic_arm = RoboticArm("notwork", "put")


# 产线验收接口
def PInput(user_input):
    if user_input == "取料":
        print(client_connection.read_holding_registers(0x0001, 1)[0])
        result = getMaterial(user_input)
        print(client_connection.read_holding_registers(0x0001, 1)[0])
        return result  # 输出处理结果

    elif user_input == "放料OK":
        print(client_connection.read_holding_registers(0x0001, 1)[0])
        result = putMaterial(user_input)  # 调用函数进行处理
        print(client_connection.read_holding_registers(0x0001, 1)[0])
        return result  # 输出处理结果

    elif user_input == "放料NG":
        print(client_connection.read_holding_registers(0x0001, 1)[0])
        result = putMaterial(user_input)  # 调用函数进行处理
        print(client_connection.read_holding_registers(0x0001, 1)[0])
        return result  # 输出处理结果

    else:
        return "无效的命令"

    # 关闭连接
    client_connection.close()


# 3D大屏接口
def PInput3D(user_input):
    if user_input == "取料":
        getMaterial(user_input)
        # 获取当前龙门的状态
        # result = getHouseStatus(user_input)
        # 返回当前龙门的状态给调用它的接口
        # getLongMenResult.get_LongMenResult(result)
        # 设置时间，过了设定的时间就对龙门的状态进行更新
        time.sleep(5)  # 龙门寄存器的值是否可以读取
        # 获取龙门新的状态
        robotic_arm.work = "Not Work"  # 首先改变龙门机械臂的工作状态
        # result = getHouseStatus(user_input)
        # 返回龙门新的状态给调用它的接口
        # getLongMenResult.get_LongMenResult(result)
        # return result

    elif user_input == "放料OK":
        putMaterial(user_input)
        # result = getHouseStatus(user_input)

        time.sleep(5)
        robotic_arm.work = "Not Work"
        # return result

    elif user_input == "放料NG":
        putMaterial(user_input)  # 调用函数进行处理
        # result = getHouseStatus(user_input)
        time.sleep(5)
        robotic_arm.work = "Not Work"
        # return result

    else:
        return "无效的命令"
